/***************************************************************************
 *   Copyright (C) 2004 by Nilesh Bansal                                   *
 *   nilesh@iitb.ac.in                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "ftpmonitor.h"

#include <QGraphicsTextItem>
#include <QTreeView>
#include <QHeaderView>
#include <QStringListModel>
#include <QTableWidget>
#include <QPainter>
#include <QFont>
#include <QDir>

#include <KConfigDialog>
#include <KNotification>
#include <KGlobal>
#include <KStandardDirs>
#include <KMessageBox>
#include <KDebug>

#include <Plasma/Applet>

//if config wasn't created yet,default ftp server is proftpd
#define DEFAULT_FTP_SERVER 1
//if config wasn't created yet,update interval is 2
#define DEFAULT_UPDATE_INTERVAL 2

FTPMonitor::FTPMonitor(QObject *parent, const QVariantList &args)
: Plasma::PopupApplet(parent, args), mListView( 0 )
{	
	setAspectRatioMode(Plasma::IgnoreAspectRatio);
	setHasConfigurationInterface(true);
}

FTPMonitor::~FTPMonitor()
{	
}

void FTPMonitor::init()
{
	KConfigGroup cg = config();

	//check chosen ftp server if we start applet first time use proftpd as default
	FTPMonitorLoop::FtpServerType ftpServerType = (FTPMonitorLoop::FtpServerType) cg.readEntry("chosenFtpServer", DEFAULT_FTP_SERVER);
	//check if we want use specific path for ftpwho command
	bool usePath = cg.readEntry("useOwnPathForFtpWho", false);
	QString whoPath = "";
	if (usePath==true){
		whoPath = cg.readEntry("ownFtpWhoPath", "");
	}
	//check if we need sudo for ftpwho command
	bool useSudo = cg.readEntry("useSudo",false);
	bool allowPopup = cg.readEntry("allowPopup",true);
	int updateInterval = cg.readEntry("updateInterval",DEFAULT_UPDATE_INTERVAL);

	mShowNumberInSystray = cg.readEntry("numberInSystray",true);
	
	mMonitorLoop = newFtpMonitor(ftpServerType,whoPath,useSudo);

	connect(mMonitorLoop,SIGNAL(sigNewClientsConnected(int)), this,SLOT(newClientsConnected(int)));
	connect(mMonitorLoop,SIGNAL(sigClientsCountChanged(int)), this,SLOT(setSystrayIcon(int)));
	connect(mMonitorLoop,SIGNAL(sigErrorOccurs(int,QString)), this,SLOT(errorOccurs(int,QString)));
	
	connect(mMonitorLoop,SIGNAL(sigAddRow(QStringList)),this,SLOT(addRow(QStringList)));
	connect(mMonitorLoop,SIGNAL(sigDelRow(int)),this,SLOT(delRow(int)));
	connect(mMonitorLoop,SIGNAL(sigChangeRow(QStringList,int)),this,SLOT(changeRow(QStringList,int)));
	
	mMonitorLoop->start(updateInterval,allowPopup);
}

QWidget *FTPMonitor::widget()
{
	if (!mListView){
		mListView = new QTreeWidget();
		
		mListView->setAttribute(Qt::WA_NoSystemBackground);
		mListView->setEditTriggers( QAbstractItemView::NoEditTriggers );
		mListView->setRootIsDecorated(false);
		mListView->setMouseTracking(true);

		mListView->setColumnCount(5);
		
		mListView->header()->setResizeMode(0,QHeaderView::ResizeToContents);
		mListView->header()->setResizeMode(1,QHeaderView::ResizeToContents);
		mListView->header()->setResizeMode(2,QHeaderView::ResizeToContents);
		mListView->header()->setResizeMode(3,QHeaderView::ResizeToContents);
		mListView->header()->setResizeMode(4,QHeaderView::Stretch);
		
		setHeaderLabels(mMonitorLoop->ftpServerType());
	}
	return mListView;
}	

////////////////////////////////////////////////////////////////////
////////////////config windows//////////////////////////////////////
////////////////////////////////////////////////////////////////////
void FTPMonitor::btnconfFtpdTypeToggled(bool checked)
{
	QRadioButton* btn = qobject_cast<QRadioButton *>(QObject::sender());
	if (btn && checked)
	{
		if ( btn->objectName()==mUiConfig.proftpdRadioButton->objectName() )
		{
			mUiConfig.chkBoxUsePath->setEnabled(true);
			mUiConfig.chkBoxUsePath->setText(
			QString("Set the directory where is your \"%1\" binary placed.").arg(ProftpdMonitor::ftpWhoBinaryName()));
			mUiConfig.stackFtpWhoPath->setCurrentIndex(0);
			mUiConfig.chBoxUseSudo->setText(
			QString("Use sudo -n command for \"%1\" binary.").arg(ProftpdMonitor::ftpWhoBinaryName()) );
			
		}
		else if ( btn->objectName()==mUiConfig.ncftpdRadioButton->objectName() )
		{
			mUiConfig.chkBoxUsePath->setEnabled(true);
			mUiConfig.chkBoxUsePath->setText(
			QString("Set the directory where is your \"%1\" binary placed.").arg(NcftpdMonitor::ftpWhoBinaryName()));
			mUiConfig.chBoxUseSudo->setText(
			QString("Use sudo -n command for \"%1\" binary.").arg(NcftpdMonitor::ftpWhoBinaryName()) );
			mUiConfig.stackFtpWhoPath->setCurrentIndex(0);
		}
		else if ( btn->objectName()==mUiConfig.pureftpdRadioButton->objectName() )
		{
			mUiConfig.chkBoxUsePath->setEnabled(true);
			mUiConfig.chkBoxUsePath->setText(
			QString("Set the directory where is your \"%1\" binary placed.").arg(PureftpdMonitor::ftpWhoBinaryName()));
			mUiConfig.chBoxUseSudo->setText(
			QString("Use sudo -n command for \"%1\" binary.").arg(PureftpdMonitor::ftpWhoBinaryName()) );
			mUiConfig.stackFtpWhoPath->setCurrentIndex(0);
		}
		else if ( btn->objectName()==mUiConfig.vsftpdRadioButton->objectName() )
		{
			mUiConfig.lblNoFtpWho->setText(
			QString("For vsftpd daemon is used \"ps\" command \nto find out connected clients."));
			mUiConfig.stackFtpWhoPath->setCurrentIndex(1);
		}
	}
}

void FTPMonitor::createConfigurationInterface(KConfigDialog *parent)
{
	QWidget *widget = new QWidget(parent);
	mUiConfig.setupUi(widget);
	parent->addPage(widget, i18n("General"), icon());
	connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
	connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
	connect(mUiConfig.proftpdRadioButton, SIGNAL(toggled(bool)), this, SLOT(btnconfFtpdTypeToggled(bool)));
	connect(mUiConfig.vsftpdRadioButton, SIGNAL(toggled(bool)), this, SLOT(btnconfFtpdTypeToggled(bool)));
	connect(mUiConfig.pureftpdRadioButton, SIGNAL(toggled(bool)), this, SLOT(btnconfFtpdTypeToggled(bool)));
	connect(mUiConfig.ncftpdRadioButton, SIGNAL(toggled(bool)), this, SLOT(btnconfFtpdTypeToggled(bool)));

	KConfigGroup cg = config();
	FTPMonitorLoop::FtpServerType ftpServer = (FTPMonitorLoop::FtpServerType) cg.readEntry("chosenFtpServer", DEFAULT_FTP_SERVER);
	
	//check chosed ftp server
	if (ftpServer == FTPMonitorLoop::proftpd){
		mUiConfig.proftpdRadioButton->setChecked(true);
	}
	else if (ftpServer == FTPMonitorLoop::pureftpd){
		mUiConfig.pureftpdRadioButton->setChecked(true);
	}
	else if (ftpServer == FTPMonitorLoop::vsftpd){
		mUiConfig.vsftpdRadioButton->setChecked(true);
	}
	else if (ftpServer == FTPMonitorLoop::ncftpd){
		mUiConfig.ncftpdRadioButton->setChecked(true);
	}

	bool usePath = cg.readEntry("useOwnPathForFtpWho",false);
	mUiConfig.chkBoxUsePath->setChecked(usePath);
	QString whoPath = cg.readEntry("ownFtpWhoPath");

	//we will set path even if lineEdit is disabled
	mUiConfig.lineEditUsePath->setText(whoPath);
	mUiConfig.lineEditUsePath->setEnabled(usePath);

	//
	bool useSudo = cg.readEntry("useSudo",false);
	mUiConfig.chBoxUseSudo->setChecked(useSudo);
	
	bool allowPopup = cg.readEntry("allowPopup",true);
	mUiConfig.chBoxAllowPopup->setChecked(allowPopup);
	
	int  updateInterval = cg.readEntry("updateInterval",DEFAULT_UPDATE_INTERVAL);
	mUiConfig.spinBoxUpdateInterval->setValue(updateInterval);
	
	bool showNumberInSystray = cg.readEntry("numberInSystray",true);
	mUiConfig.chBoxShowNumberInSystray->setChecked(showNumberInSystray);
	
	//kDebug(1234) << ftpServer << useSudo << allowPopup << updateInterval << showNumberInSystray;
}

void FTPMonitor::configAccepted()
{
	QString whoPath;
	KConfigGroup cg = config();
	FTPMonitorLoop::FtpServerType ftpServerType;
	FTPMonitorLoop::FtpServerType oldFtpServerType = (FTPMonitorLoop::FtpServerType) cg.readEntry("chosenFtpServer", DEFAULT_FTP_SERVER);
	
	if (mUiConfig.pureftpdRadioButton->isChecked()){
		ftpServerType=FTPMonitorLoop::pureftpd;
	}
	else if (mUiConfig.proftpdRadioButton->isChecked()){
		ftpServerType=FTPMonitorLoop::proftpd;
	}
	else if (mUiConfig.vsftpdRadioButton->isChecked()){
		ftpServerType=FTPMonitorLoop::vsftpd;
	}
	else if (mUiConfig.ncftpdRadioButton->isChecked()){
		ftpServerType=FTPMonitorLoop::ncftpd;
	}
	
	bool usePath = mUiConfig.chkBoxUsePath->isChecked();

	cg.writeEntry("chosenFtpServer", (int)ftpServerType);
	cg.writeEntry("useOwnPathForFtpWho", usePath);
	
	if (usePath==true){
		whoPath = mUiConfig.lineEditUsePath->text();
		cg.writeEntry("ownFtpWhoPath", whoPath);
	}
	
	bool useSudo = mUiConfig.chBoxUseSudo->isChecked();
	cg.writeEntry("useSudo", useSudo);
	
	bool allowPopup = mUiConfig.chBoxAllowPopup->isChecked();
	cg.writeEntry("allowPopup", allowPopup);
	
	int updateInterval = mUiConfig.spinBoxUpdateInterval->value();
	cg.writeEntry("updateInterval", updateInterval);
	
	mShowNumberInSystray = mUiConfig.chBoxShowNumberInSystray->isChecked();
	cg.writeEntry("numberInSystray",mShowNumberInSystray);
	
	//TODO: next steps should not be used every time, e.g if user change only allowPopup we don't need restart qtimer
	//if user hit ok stop qtimer
	mMonitorLoop->stop();
	//clear ui
	clearClientsTable();
	//set propper header according to chosen ftpserver
	setHeaderLabels(ftpServerType);
	//if we are changing ftpserver type we have to delete old and create new class because we use polymorfism
	//ARGHHHH i have to clean up this
	if (oldFtpServerType!=ftpServerType)
	{
		delete mMonitorLoop;
		mMonitorLoop = newFtpMonitor(ftpServerType,whoPath,useSudo);
		connect(mMonitorLoop,SIGNAL(sigNewClientsConnected(int)), this,SLOT(newClientsConnected(int)));
		connect(mMonitorLoop,SIGNAL(sigClientsCountChanged(int)), this,SLOT(setSystrayIcon(int)));
		connect(mMonitorLoop,SIGNAL(sigErrorOccurs(int,QString)), this,SLOT(errorOccurs(int,QString)));

		connect(mMonitorLoop,SIGNAL(sigAddRow(QStringList)),this,SLOT(addRow(QStringList)));
		connect(mMonitorLoop,SIGNAL(sigDelRow(int)),this,SLOT(delRow(int)));
		connect(mMonitorLoop,SIGNAL(sigChangeRow(QStringList,int)),this,SLOT(changeRow(QStringList,int)));
	}  
	else
	{
		//create new command which will be executed each x seconds
		mMonitorLoop->createExecCommand(useSudo,whoPath);
	}
	//start qtimer
	mMonitorLoop->start(updateInterval,allowPopup);

	emit configNeedsSaving();
}

/////////////////////////////////////////////////////////////////////
//////////////////end of config window///////////////////////////////
////////////////////////////////////////////////////////////////////

FTPMonitorLoop* FTPMonitor::newFtpMonitor(FTPMonitorLoop::FtpServerType ftpType,QString whoPath,bool useSudo)
{
	switch(ftpType)
	{
		case FTPMonitorLoop::proftpd:
		    return new ProftpdMonitor(whoPath,useSudo);
		case FTPMonitorLoop::pureftpd:
			return new PureftpdMonitor(whoPath,useSudo);
		case FTPMonitorLoop::vsftpd:
			return new VsftpdMonitor(whoPath,useSudo);
		case FTPMonitorLoop::ncftpd:
			return new NcftpdMonitor(whoPath,useSudo);
		default:
			return 0;
	}
}

void FTPMonitor::clearClientsTable()
{
	mListView->clear();
}

void FTPMonitor::setHeaderLabels(FTPMonitorLoop::FtpServerType ftpServer)
{
	switch (ftpServer)
	{
		case FTPMonitorLoop::proftpd :
			mListView->setHeaderLabels(QStringList() << "PID" << "Login" << "What" << "Client" << "Location");
			break;
		case FTPMonitorLoop::pureftpd :
			//pid|acct|time|state|file|peer|local|port|current|total|%|bandwidth
			//mListView->setHeaderLabels(QStringList() << "PID" << "Login" << "State" << "Host");
			mListView->setHeaderLabels(QStringList() << "PID" << "Login" << "State" << "File" << "Host");
			break;
		case FTPMonitorLoop::vsftpd :
			//ftp      18677 18675  0 09:30 ?        00:00:00 vsftpd: 10.20.1.244/ftp: RETR /uploads/archlinux-2009.02-core-i686.iso
			//ftp      18699 18697  0 09:30 ?        00:00:00 vsftpd: 10.20.1.244/ftp: IDLE
			mListView->setHeaderLabels(QStringList() << "PID" << "Login" << "State" << "File" << "Host");
			break;
		case FTPMonitorLoop::ncftpd :
			mListView->setHeaderLabels(QStringList() << "PID" << "Login" << "State" << "Location" << "Host");
			break;
	}
}

void FTPMonitor::setSystrayIcon(int count)
{
	QString imgName;

	if (count < 0)
		imgName="ftpmonitor-error.png";	
	else if (count > 0)
		imgName="ftpmonitor-connected.png";
	else
		imgName="ftpmonitor-disconnected.png";
	
	//see http://mail.kde.org/pipermail/plasma-devel/2008-November/002279.html for recognize propper path name
	QString iconPath = KGlobal::dirs()->locate("data", "plasma/plasmoids/ftpmonitor/" + imgName);
	
	if (mShowNumberInSystray==false || count<=0)
	{
		setPopupIcon(iconPath);
		return;
	}
	
	QString clientCount(QString("%1").arg(count));

	QPixmap icon;
	icon.load(iconPath);;
	
	//draw bigger "backround" number (for nicer effect)
	QPainter p(&icon);
	QFont font(p.font());
	font.setPointSize(20);
	font.setBold(true);
	p.setFont(font);
	p.setPen("gray");
	p.drawText(QRect(0, 0, icon.width(), icon.height()), Qt::AlignCenter, clientCount);
	p.end();	
	
	//draw smaller "number" in front (for nicer effect)
	QPainter p2(&icon);
	QFont font2(p2.font());
	font2.setPointSize(18);
	font2.setBold(false);
	p2.setFont(font2);
	p2.setPen("black");
	p2.drawText(QRect(0, 0, icon.width(), icon.height()), Qt::AlignCenter, clientCount);
	p2.end();
	
	setPopupIcon(icon);
}

void FTPMonitor::newClientsConnected(int count)
{
	QString popupText;
	if (count > 1)
		popupText=i18n("New clients connected");
	else
		popupText=i18n("New client connected");
	
	KNotification::event(  "client_connected", popupText, QPixmap(), 0, KNotification::CloseOnTimeout,
		 KComponentData("ftpmonitor", "ftpmonitor", KComponentData::SkipMainComponentRegistration) );
}

void FTPMonitor::errorOccurs(int , QString errMsg)
{
	QString popupText;

	setSystrayIcon(-1);
	//todo use Persistent instead of knotification::closeontimeout if it will be fixed
	KNotification::event(  "error_occurs", errMsg, QPixmap(), 0, KNotification::CloseOnTimeout,
		 KComponentData("ftpmonitor", "ftpmonitor", KComponentData::SkipMainComponentRegistration) );
}

void FTPMonitor::delRow(int row)
{
	delete mListView->takeTopLevelItem(row);
}

void FTPMonitor::addRow(QStringList row)
{
	mListView->addTopLevelItem(new QTreeWidgetItem((QTreeWidgetItem*)0,row));
}

void FTPMonitor::changeRow(QStringList newRow,int id)
{
	delRow(id);
	mListView->insertTopLevelItem(id,new QTreeWidgetItem((QTreeWidgetItem*)0,newRow));
}

#include "ftpmonitor.moc"
